#ifndef _COMPAT_EVENTS_IOCP_H_
#define _COMPAT_EVENTS_IOCP_H_

#ifdef __cplusplus
extern "C" {
#endif

#include <crt_util.h>
#include "compat_event_util.h"

#if (TARGET_OS == OS_WIN)

#include <MSWSock.h>

#define iocp_completion ((ULONG_PTR)2000)
#define iocp_exit       ((ULONG_PTR)3000)

typedef struct extension_fns_ex extension_fns;
typedef struct iocp_op_s iocp_op_t;
typedef struct iocp_fns_ex iocp_fns;

#ifndef WSAID_ACCEPTEX
#define WSAID_ACCEPTEX \
    { \
        0xb5367df1, 0xcbac, 0x11cf, \
        { \
            0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92 \
        } \
    }
#endif

#ifndef WSAID_CONNECTEX
#define WSAID_CONNECTEX \
    { \
        0x25a207b9, 0xddf3, 0x4660, \
        { \
            0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e \
        } \
    }
#endif

#ifndef WSAID_GETACCEPTEXSOCKADDRS
#define WSAID_GETACCEPTEXSOCKADDRS \
    { \
        0xb5367df2, 0xcbac, 0x11cf, \
        { \
            0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92 \
        } \
    }
#endif

#ifndef WSAID_DISCONNECTEX
#define WSAID_DISCONNECTEX \
    { \
        0x7fda2e11, 0x8630, 0x436f, \
        { \
            0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57 \
        } \
    }
#endif

typedef BOOL(WINAPI* AcceptExPtr)(SOCKET, SOCKET, PVOID, DWORD, DWORD, DWORD, LPDWORD, LPOVERLAPPED);
typedef BOOL(WINAPI* ConnectExPtr)(SOCKET, const struct sockaddr*, int, PVOID, DWORD, LPDWORD, LPOVERLAPPED);
typedef void(WINAPI* GetAcceptExSockaddrsPtr)(PVOID, DWORD, DWORD, DWORD, LPSOCKADDR*, LPINT, LPSOCKADDR*, LPINT);
typedef BOOL(WINAPI* DisconnectExPtr)(SOCKET, LPOVERLAPPED, DWORD, DWORD);
typedef ULONGLONG(WINAPI* GetTickCount64_func)(void);
typedef DWORD(WINAPI* GetTickCount_func)(void);

typedef BOOL(WINAPI* CancelIoPtr)(HANDLE);
typedef BOOL(WINAPI* CancelIoExPtr)(HANDLE, LPOVERLAPPED);
typedef BOOL(WINAPI* CancelSynchronousIoPtr)(HANDLE);

struct extension_fns_ex {
    AcceptExPtr AcceptEx;
    ConnectExPtr ConnectEx;
    GetAcceptExSockaddrsPtr GetAcceptExSockaddrs;
    DisconnectExPtr DisconnectEx;
};

struct iocp_fns_ex {
    // cancelio ==> Multi threading is not supported
    CancelIoPtr CancelIo;
    // cancelioex ==> Multi threading is supported
    CancelIoExPtr CancelIoEx;
    CancelSynchronousIoPtr CancelSynchronousIo;
};

#ifndef ACCEPT_ADDRESS_LENGTH
#define ACCEPT_ADDRESS_LENGTH ((sizeof(struct sockaddr_in) + 16))
#endif // !ACCEPT_ADDRESS_LENGTH

typedef struct {
    OVERLAPPED overlapped;
    void* ptr; // lpwsascok
    char addr[ACCEPT_ADDRESS_LENGTH * 2 + 20];
    crterr error;
    evevent r;
    evevent w;

	evoper_t* oper;
	evoper_queue queue;
	
} evoper_ov, *lpevoper_ov;

typedef struct {
    evoper_t* accept_oper;
    evoper_t* oper;
} wsasock, *lpwsasock;

struct iocp_op_s {
    HANDLE hiocp;
    extension_fns fns;
    iocp_fns iocp;
    int size;

    _thread_t waitsem_thread;
    _cond_t waitcond;
    _mutex_t waitlock;
    ev_op ev;
	
	_mutex_t lock;
	evloop_queue_t queue;
};

int iocp_evop_t(evsysop_t* op);
int evoper_ov_bind_ptr(evoper_ov* ov, void* ptr);
int wsasock_create(evloop_t* loop, iocp_op_t* base, evoper_t* oper_s, wsasock** sock);

#ifdef __cplusplus
}
#endif

#endif

#endif
